/*数据*/
const redis = require("redis");
const redis_client = redis.createClient();
const bluebird = require("bluebird");
bluebird.promisifyAll(redis.RedisClient.prototype);
bluebird.promisifyAll(redis.Multi.prototype);

exports.redis_client = redis_client;
const redis_prefix =
  "13shui-" + (Date.now() - new Date("2017/4/18")).toString(36);
exports.redis_prefix = redis_prefix;

redis_client.on("error", function(err) {
  console.error("Redis Error :", err);
});

redis_client.writeObjectAsync = function(key, obj) {
  return redis_client.writeStringAsync(key, JSON.stringify(obj));
};
redis_client.writeStringAsync = function(key, str) {
  return new Promise(async (resolve, reject) => {
    let i = 0;
    let res;
    do {
      i += 1;
      res = await redis_client.setAsync(key, str);
      try {
        if ((await redis_client.getAsync(key)) === str) {
          console.log("REDIS写入成功，结束循环");
          break;
        }
      } catch (e) {}
      console.log("REDIS写入失败，重新写入", res);
      if (i >= 10) {
        //写入10次都失败的话，报错
        reject(new Error("数据库异常，写入失败次数过多，中断写入"));
        return;
      }
    } while (true);
    resolve(res);
  });
};
// 删除之前使用的redis数据
(async () => {
  const pre_redis_prefix =
    (await redis_client.getAsync("13shui-pre_redis_prefix")) || "13shui-";
  console.log("pre_redis_prefix", pre_redis_prefix);

  let cursor = "0";
  await new Promise(cb => {
    function scan() {
      redis_client.scan(
        cursor,
        "MATCH",
        pre_redis_prefix + "*",
        "COUNT",
        "10",
        function(err, res) {
          if (err) throw err;
          cursor = res[0];
          const keys = res[1];

          if (keys.length > 0) {
            // console.log("Array of matching keys", keys);
            keys.forEach(key => {
              redis_client.del(key);
            });
          }
          if (cursor === "0") {
            console.log("遗留旧数据删除完成");
            cb();
          } else {
            scan();
          }
        }
      );
    }
    scan();
  });
  redis_client.writeStringAsync("13shui-pre_redis_prefix", redis_prefix);
})();

/*加密*/
const crypto = require("crypto");
const md5 = function(str) {
  const md5sum = crypto.createHash("md5");
  md5sum.update(str);
  str = md5sum.digest("hex");
  return str;
};
exports.md5 = md5;

function hashToSexId(hash) {
  let res = 0;
  res += 9 / 0xfffff * parseInt(hash.substr(0, 5), 16) * 100000;
  res += 9 / 0xfffff * parseInt(hash.substr(5, 5), 16) * 10000;
  res += 9 / 0xfffff * parseInt(hash.substr(10, 5), 16) * 1000;
  res += 9 / 0xfffff * parseInt(hash.substr(15, 5), 16) * 100;
  res += 9 / 0xfffff * parseInt(hash.substr(20, 5), 16) * 10;
  res += 9 / 0xfffff * parseInt(hash.substr(25, 5), 16);
  if (parseInt(hash.substr(-2), 16) > 128) {
    res += 1;
  }
  return ((res / 1000000).toString() + "000000").split(".")[1].substr(0, 6);
}
exports.hashToSexId = hashToSexId;

/* 异步控制相关的辅助函数 */
const isAsyncFunction = (exports.isAsyncFunction = (() => {
  const a = async a => a;
  const AsyncFunction = a.constructor;
  return fun => fun instanceof AsyncFunction;
})());
exports.sleep = time => {
  return new Promise(cb => setTimeout(cb, time));
};

/*代理*/
const caw = require("caw");
const https = require("https");

if (process.argv.indexOf("--without-proxy") == -1) {
  https.globalAgent = caw("http://127.0.0.1:8118", {
    protocol: "https"
  });
}

const admin = require("./firebase-admin");
exports.fbadmin = admin;

const serviceAccount = require("./config/shui-35c19-firebase-adminsdk-wfv5e-5dae6ee173.json");
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://shui-35c19.firebaseio.com",
  agent: https.globalAgent
});
const db = admin.database();
exports.db = db;

const koaBody = require("koa-body")();
exports.bodyParser = ctx => {
  return new Promise((resolve, reject) => {
    koaBody(ctx, () => {
      resolve(ctx.request.body);
    }).catch(reject);
  });
};

exports.dbPromiss = exports.dbPromise = (db_ref, options = {}) => {
  const { can_null, null_errormsg = "找不到指定数据" } = options;
  return new Promise((resolve, reject) => {
    db_ref.once(
      "value",
      snapshot => {
        const val = snapshot.val();
        if (val || can_null) {
          resolve(val);
        } else {
          reject(null_errormsg);
        }
      },
      reject
    );
  });
};

/* 事件绑定*/

const successRes = (exports.successRes = data => {
  return {
    status: "success",
    data
  };
});
const errorRes = (exports.errorRes = err => {
  return {
    status: "error",
    msg: err instanceof Error ? err.message : String(err)
  };
});

exports.on = function on(events, eventname, callback, on_error) {
  on_error ||
    (on_error = err => {
      console.error(err);
      events.emit("res-error", errorRes(err));
    });

  let bind_handle;
  let remove_lis = () => {
    console.log("移除绑定", eventname);
    events.removeListener(eventname, bind_handle);
  };
  if (isAsyncFunction(callback)) {
    events.on(
      eventname,
      (bind_handle = async (...args) => {
        try {
          await callback(...args);
        } catch (e) {
          on_error(e);
        }
      })
    );
  } else {
    events.on(
      eventname,
      (bind_handle = (...args) => {
        try {
          callback(...args);
        } catch (e) {
          on_error(e);
        }
      })
    );
  }
  return remove_lis;
};
/* 上帝监控器 */
const EventEmitter = require("events");
const adminEvents = (exports.adminEvents = new EventEmitter());
adminEvents.setMaxListeners(10000);
